Security News
PyPI Introduces Digital Attestations to Strengthen Python Package Security
PyPI now supports digital attestations, enhancing security and trust by allowing package maintainers to verify the authenticity of Python packages.
ts-essentials
Advanced tools
The ts-essentials package provides a set of TypeScript types to enhance the TypeScript typing experience, offering more strict and powerful type definitions. It includes utility types, type guards, and other helpers that are not available in the standard TypeScript library.
DeepReadonly
Makes all properties of an object type recursively readonly. It is useful for defining immutable state or configurations.
type MyObject = { a: { b: { c: number } } };\nconst readonlyObject: DeepReadonly<MyObject> = { a: { b: { c: 1 } } };\n// readonlyObject.a.b.c = 2; // Error: Cannot assign to 'c' because it is a read-only property.
Writable
Converts a readonly object into a writable one, removing the readonly modifier from all properties.
type MyReadOnlyObject = { readonly a: number };\nconst writable: Writable<MyReadOnlyObject> = { a: 1 };\nwritable.a = 2; // No error, 'a' is writable.
StrictOmit
Creates a type by omitting the keys provided from the given object type, ensuring that only keys that exist on the type are specified.
interface MyObject { a: number; b: string; c: boolean; }\nconst myObject: StrictOmit<MyObject, 'a' | 'b'> = { c: true };\n// myObject.a or myObject.b does not exist.
LiteralUnion
Allows for a union type to include specific literal types as well as additional types, typically used for string literals with an escape hatch for other values.
type Direction = LiteralUnion<'left' | 'right', string>;\nconst direction: Direction = 'any string'; // No error, can be 'left', 'right', or any other string.
MarkRequired
Marks certain properties of an object type as required, changing them from optional to mandatory.
type MyObject = { a?: number; b: string; }\nconst required: MarkRequired<MyObject, 'a'> = { a: 1, b: 'string' };\n// Property 'a' is required in 'required'.
Provides a collection of utility types for TypeScript, similar to ts-essentials. It includes types for operations like picking, omitting, and mapping properties of object types.
A comprehensive library of utility types for TypeScript, with a wide range of type helpers. It covers more ground than ts-essentials and is regularly updated with new types.
Focused on Redux action creators, typesafe-actions provides utility types and functions for creating and handling actions in a type-safe manner, which is a more specific use case compared to the general utilities provided by ts-essentials.
All essential TypeScript types in one place π€
npm install --save-dev ts-essentials
π We require typescript>=3.7
. If you're looking for support for older TS versions use ts-essentials@3
(for 3.6>=)
or ts-essentials@2
instead.
Primitive
type matching all primitive values.noop
function that takes any arguments and returns nothing, as a placeholder for e.g. callbacks.keywords: map
const stringDict: Dictionary<string> = {
a: "A",
b: "B",
};
// Specify second type argument to change dictionary keys type
const dictOfNumbers: Dictionary<string, number> = {
420: "four twenty",
1337: "HAX",
};
// You may specify union types as key to cover all possible cases. It acts the same as Record from TS's standard library
export type DummyOptions = "open" | "closed" | "unknown";
const dictFromUnionType: Dictionary<number, DummyOptions> = {
closed: 1,
open: 2,
unknown: 3,
};
// and get dictionary values
type stringDictValues = DictionaryValues<typeof stringDict>;
// Result: string
// When building a map using JS objects consider using SafeDictionary
const safeDict: SafeDictionary<number> = {};
const value: number | undefined = safeDict["foo"];
keywords: recursive, nested, optional
type ComplexObject = {
simple: number;
nested: {
a: string;
array: [{ bar: number }];
};
};
type ComplexObjectPartial = DeepPartial<ComplexObject>;
const samplePartial: ComplexObjectPartial = {
nested: {
array: [{}],
},
};
type ComplexObjectAgain = DeepRequired<ComplexObjectPartial>;
const sampleRequired: ComplexObjectAgain = {
simple: 5,
nested: {
a: "test",
array: [{ bar: 1 }],
},
};
type ComplexObjectReadonly = DeepReadonly<ComplexObject>;
type ComplexNullableObject = {
simple: number | null | undefined;
nested: {
a: string | null | undefined;
array: [{ bar: number | null | undefined }] | null | undefined;
};
};
type ComplexObjectNonNullable = DeepNonNullable<ComplexNullableObject>;
const sampleNonNullable: ComplexObjectNonNullable = {
simple: 5,
nested: {
a: "test",
array: [{ bar: null }], // Error: Type 'null' is not assignable to type 'number'
},
};
type ComplexObjectNullable = DeepNullable<ComplexObject>;
const sampleDeepNullable1: ComplexObjectNullable = {
simple: null,
nested: {
a: null,
array: [{ bar: null }],
},
};
const sampleDeepNullable2: ComplexObjectNullable = {
simple: 1,
nested: {
array: [null], // OK
// error -- property `a` missing, should be `number | null`
},
};
// DeepUndefinable will come in handy if:
// - you want to explicitly assign values to all of the properties
// AND
// - the expression used for the assignment can return an `undefined` value
// In most situations DeepPartial will suffice.
declare function tryGet(name: string): string | undefined;
type ComplexObjectUndefinable = DeepUndefinable<ComplexObject>;
const sampleDeepUndefinable1: ComplexObjectUndefinable = {
simple: undefined,
nested: {
a: tryGet('a-value'),
array: [{ bar: tryGet('bar-value') }]
}
}
const sampleDeepUndefinable2: ComplexObjectUndefinable = {
// error -- property `simple` missing, should be `number | undefined`
nested: {
array: [[{ bar: undefined }]]
// error -- property `a` missing, should be `string | undefined`
}
}
Make all attributes of object writable.
type Foo = {
readonly a: number;
readonly b: string;
};
const foo: Foo = ({ a: 1, b: "b" }(foo as Writable<typeof foo>).a = 42);
type Foo = {
readonly foo: string;
bar: {
readonly x: number;
};
}[];
const test: DeepWritable<Foo> = [
{
foo: "a",
bar: {
x: 5,
},
},
];
// we can freely write to this object
test[0].foo = "b";
test[0].bar.x = 2;
keywords: builder
A combination of both DeepWritable
and DeepPartial
. This type allows building an object step-by-step by assigning
values to its attributes in multiple statements.
interface ReadonlyObject
extends Readonly<{
simple: number;
nested: Readonly<{
a: string;
array: ReadonlyArray<Readonly<{ bar: number }>>;
}>;
}> {}
const buildable: Buildable<ReadonlyObject> = {};
buildable.simple = 7;
buildable.nested = {};
buildable.nested.a = "test";
buildable.nested.array = [];
buildable.nested.array.push({ bar: 1 });
const finished = buildable as ReadonlyObject;
Our version of Omit
is renamed to StrictOmit
in v3
, since the builtin Omit
has become part of TypeScript 3.5
Usage is similar to the builtin version, but checks the filter type more strictly.
type ComplexObject = {
simple: number;
nested: {
a: string;
array: [{ bar: number }];
};
};
type SimplifiedComplexObject = StrictOmit<ComplexObject, "nested">;
// Result:
// {
// simple: number
// }
// if you want to Omit multiple properties just use union type:
type SimplifiedComplexObject = StrictOmit<ComplexObject, "nested" | "simple">;
// Result:
// { } (empty type)
Omit
and StrictOmit
Following the code above, we can compare the behavior of Omit
and StrictOmit
.
type SimplifiedComplexObjectWithStrictOmit = StrictOmit<ComplexObject, "nested" | "simple" | "nonexistent">;
// Result: error
// Type '"simple" | "nested" | "nonexistent"' does not satisfy the constraint '"simple" | "nested"'.
// Type '"nonexistent"' is not assignable to type '"simple" | "nested"'.
type SimplifiedComplexObjectWithOmit = Omit<ComplexObject, "nested" | "simple" | "nonexistent">;
// Result: no error
As is shown in the example, StrictOmit
ensures that no extra key is specified in the filter.
Recursively omit deep properties according to key names.
Here is the Teacher
interface.
interface Teacher {
name: string;
gender: string;
students: { name: string; score: number }[];
}
Now suppose you want to omit gender
property of Teacher
, and score
property of students
. You can achieve this
with a simple type filter.
In the filter, the properties to be omitted completely should be defined as never
. For the properties you want to
partially omit, you should recursively define the sub-properties to be omitted.
type TeacherSimple = DeepOmit<
Teacher,
{
gender: never;
students: {
score: never;
};
}
>;
// The result will be:
// {
// name: string,
// students: {name: string}[]
// }
NOTE
DeepOmit
works fine with Array
s and Set
s. When applied to a Map
, the filter is only applied to its value.keywords: filter, props
Removes all properties extending type P
in type T
. NOTE: it works opposite to filtering.
interface Example {
log(): void;
version: string;
}
type ExampleWithoutMethods = OmitProperties<Example, Function>;
// Result:
// {
// version: string;
// }
// if you want to Omit multiple properties just use union type like
type ExampleWithoutMethods = OmitProperties<Example, Function | string>;
// Result:
// { } (empty type)
Pick only properties extending type P
in type T
.
interface Example {
log(): void;
version: string;
versionNumber: number;
}
type ExampleOnlyMethods = PickProperties<Example, Function>;
// Result:
// {
// log(): void;
// }
// if you want to pick multiple properties just use union type like
type ExampleOnlyMethodsAndString = PickProperties<Example, Function | string>;
// Result:
// {
// log(): void;
// version: string;
// }
Useful for purifying object types. It improves intellisense but also allows for extracting keys satisfying a conditional type.
type GetDefined<TypesMap extends { [key: string]: any }> = keyof NonNever<
{ [T in keyof TypesMap]: TypesMap[T] extends undefined ? never : TypesMap[T] }
>;
Useful for accepting only objects with keys, great after a filter like OmitProperties or PickProperties.
/* return never if the object doesn't have any number value*/
type NumberDictionary<T> = NonEmptyObject<PickProperties<T, number>>;
// return { a: number }
type SomeObject = NumberDictionary<{ a: number; b: string }>;
// return never
type EmptyObject = NumberDictionary<{}>;
keywords: override
type Foo = {
a: number;
b: string;
};
type Bar = {
b: number;
};
const xyz: Merge<Foo, Bar> = { a: 4, b: 2 };
// Result:
// {
// a: number,
// b: number,
// }
Useful when you're sure some optional properties will be set. A real life example: when selecting an object with its related entities from an ORM.
class User {
id: number;
posts?: Post[];
photos?: Photo[];
}
type UserWithPosts = MarkRequired<User, "posts">;
// example usage with a TypeORM repository -- `posts` are now required, `photos` are still optional
async function getUserWithPosts(id: number): Promise<UserWithPosts> {
return userRepo.findOneOrFail({ id }, { relations: ["posts"] }) as Promise<UserWithPosts>;
}
Useful when you want to make some properties optional without creating a separate type.
interface User {
id: number;
name: string;
email: string;
password: string;
}
type UserWithoutPassword = MarkOptional<User, "password">;
// Result:
// {
// id: number;
// name: string;
// email: string;
// password?: string;
// }
Gets keys of an object which are readonly.
type T = {
readonly a: number;
b: string;
};
type Result = ReadonlyKeys<T>;
// Result:
// "a"
Gets keys of an object which are writable.
type T = {
readonly a: number;
b: string;
};
type Result = WritableKeys<T>;
// Result:
// "b"
Gets keys of an object which are optional.
type T = {
a: number;
b?: string;
c: string | undefined;
d?: string;
};
type Result = OptionalKeys<T>;
// Result:
// "b" | "d"
Gets keys of an object which are required.
type T = {
a: number;
b?: string;
c: string | undefined;
d?: string;
};
type Result = OptionalKeys<T>;
// Result:
// "a" | "c"
Useful for converting mapped types with function values to intersection type (so in this case - overloaded function).
type Foo = {
bar: string;
xyz: number;
};
type Fn = UnionToIntersection<{ [K in keyof Foo]: (type: K, arg: Foo[K]) => any }[keyof Foo]>;
type PositiveNumber = Opaque<number, "positive-number">;
function makePositiveNumber(n: number): PositiveNumber {
if (n <= 0) {
throw new Error("Value not positive !!!");
}
return (n as any) as PositiveNumber; // this ugly cast is required but only when "producing" opaque types
}
function foo<T extends Tuple>(tuple: T): T {
return tuple;
}
const ret = foo(["s", 1]);
// return type of [string, number]
You can also parametrize Tuple
type with a type argument to constraint it to certain types, i.e.
Tuple<string | number>
.
function actOnDummyOptions(options: DummyOptions): string {
switch (options) {
case "open":
return "it's open!";
case "closed":
return "it's closed";
case "unknown":
return "i have no idea";
default:
// if you would add another option to DummyOptions, you'll get error here!
throw new UnreachableCaseError(options);
}
}
const obj = {
id: "123e4567-e89b-12d3-a456-426655440000",
name: "Test object",
timestamp: 1548768231486,
};
type objKeys = ValueOf<typeof obj>;
// Result: string | number
const array = [1, 2, true, false];
type arrayElement = ElementOf<typeof array>;
// Result: number | boolean
Useful as a return type in interfaces or abstract classes with missing implementation
interface CiProvider {
getSHA(): AsyncOrSync<string>;
// same as
getSHA(): Promise<string> | string;
}
class Circle implements CiProvider {
// implementation can use sync version
getSHA() {
return "abc";
}
}
class Travis implements CiProvider {
// implementation can use async version when needed
async getSHA() {
// do async call
return "def";
}
}
keywords: invariant
Simple runtime assertion that narrows involved types using assertion functions.
Note: This function is not purely type level and leaves minimal runtime trace in generated code.
const something: string | undefined = "abc" as any;
assert(something, "Something has to be defined!");
// from now on `something` is string, if this wouldn't be a case, assert would throw
const anything = "abc" as any;
assert(anything instanceof String, "anything has to be a string!");
// from now on `anything` is string
keywords: same, equals, equality
Exact<TYPE, SHAPE>
Checks if TYPE
is exactly the same as SHAPE
, if yes than TYPE
is returned otherwise never
.
type ABC = { a: number; b: number; c: number }
type BC = { b: number; c: number }
type C = { c: number }
Exact<ABC, C> // returns NEVER
Exact<C, C> // returns C
Gets the XOR (Exclusive-OR) type which could make 2 types exclude each other.
type A = { a: string };
type B = { a: number; b: boolean };
type C = { c: number };
let A_XOR_B: XOR<A, B>;
let A_XOR_C: XOR<A, C>;
// fail
A_XOR_B = { a: 0 };
A_XOR_B = { b: true };
A_XOR_B = { a: "", b: true };
A_XOR_C = { a: "", c: 0 }; // would be allowed with `A | C` type
// ok
A_XOR_B = { a: 0, b: true };
A_XOR_B = { a: "" };
A_XOR_C = { c: 0 };
Head
& Tail
: useful for functional programming, or as building blocks for more complex functional types.
function tail<T extends any[]>(array: T): Tail<T> {
return array.slice(1) as Tail<T>;
}
type FirstParameter<FnT extends (...args: any) => any> = FnT extends (...args: infer ArgsT) => any
? Head<ArgsT>
: never;
Thanks goes to these wonderful people (emoji key):
This project follows the all-contributors specification. Contributions of any kind welcome! Read more
FAQs
All essential TypeScript types in one place
We found that ts-essentials demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago.Β It has 3 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
PyPI now supports digital attestations, enhancing security and trust by allowing package maintainers to verify the authenticity of Python packages.
Security News
GitHub removed 27 malicious pull requests attempting to inject harmful code across multiple open source repositories, in another round of low-effort attacks.
Security News
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.